package com.kt.mes.opc;

import com.kt.mes.domain.FromMes;
import com.kt.mes.domain.OpcNode;
import com.kt.mes.domain.ToMes;
import com.kt.mes.listener.*;
import com.kt.mes.service.IOpcService;
import com.kt.mes.service.IProductStoreListService;
import com.kt.mes.service.IStockBinService;
import com.kt.mes.util.OpcUtil;
import com.kt.mes.util.WebSocketServer;
import com.ruoyi.common.exception.job.TaskException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.quartz.domain.SysJob;
import com.ruoyi.quartz.util.ScheduleUtils;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaMonitoredItem;
import org.eclipse.milo.opcua.sdk.client.api.subscriptions.UaSubscription;
import org.eclipse.milo.opcua.stack.core.AttributeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned;
import org.eclipse.milo.opcua.stack.core.types.enumerated.MonitoringMode;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemCreateRequest;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoringParameters;
import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.unit.DataUnit;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;


@Component("OpcInteface")
public class OpcInteface {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private IOpcService opcService;

    @Autowired
    private IStockBinService stockBinService;
    @Autowired
    private IProductStoreListService productStoreListService;

    @Autowired
    private Scheduler scheduler;






    //创建连接
    public void getCon(String gw, String url) {
        try {
            System.out.println("正在连接 " + url);
            OpcUaClient opc = OpcClientUtil.createClient(url, "admin", "123456", gw);
            OpcUtil.mapOpcClient.put(gw, opc);

            System.out.println("成功连接 " + url);
        } catch (Exception e) {
            System.out.println("连接失败 " + url);
            OpcUtil.mapOpcClient.put(gw, null);
            //创建定时任务 不断重连
            SysJob job = null;
            if (OpcUtil.mapOpcJob.containsKey(gw) && OpcUtil.mapOpcJob.get(gw) != null) {

                job = (SysJob) OpcUtil.mapOpcJob.get(gw);
                job.setStatus("0");
            } else {
                job = new SysJob();
                job.setCronExpression("30/30 * * * * ?");
                job.setStatus("0");
                job.setJobGroup("DEFAULT");

                job.setJobId(Long.parseLong("120" + url.split("\\.")[4]));
                job.setInvokeTarget("findOpcServerJob.findServer('" + gw + "')");
                job.setJobName("findOpc" + gw);

                OpcUtil.mapOpcJob.put(gw, job);
            }


            try {
                ScheduleUtils.createScheduleJob(scheduler, job);
            } catch (SchedulerException schedulerException) {
                schedulerException.printStackTrace();
            } catch (TaskException taskException) {
                taskException.printStackTrace();
            }
            e.printStackTrace();


        }
    }


    //工位订阅代码
    public void subscriptionOfGw(String gw){
        OpcUaClient opc = (OpcUaClient) OpcUtil.mapOpcClient.get(gw);
        UaSubscription subscription = null;


        try {
            logger.info(gw+" 开始订阅");

            if (OpcUtil.mapOpcClient.containsKey(gw+"-state") && OpcUtil.mapOpcClient.get(gw+"-state").toString().equals("reset")) {
                //重新订阅
                // System.out.println("重新连接");
                subscription = opc.getSubscriptionManager().createSubscription(1000.0).get();
            } else {
                // System.out.println("第一次连接");
                opc.connect().get();
                subscription = opc.getSubscriptionManager().createSubscription(1000.0).get();
                //创建 会话监听
                // opc.addSessionActivityListener(new OpcSessionActivityListener());
                //创建 订阅监听
                switch (gw){
                    case "gw01":
                        opc.getSubscriptionManager().addSubscriptionListener(new Gw01SubscriptionListener());
                        break;
                    case "gw02":
                        opc.getSubscriptionManager().addSubscriptionListener(new Gw02SubscriptionListener());
                        break;
                    case "gw03":
                        opc.getSubscriptionManager().addSubscriptionListener(new Gw03SubscriptionListener());
                        break;
                    case "gw04":
                        opc.getSubscriptionManager().addSubscriptionListener(new Gw04SubscriptionListener());
                        break;
                    case "gw05":
                        opc.getSubscriptionManager().addSubscriptionListener(new Gw05SubscriptionListener());
                        break;
                    case "gw06":
                        opc.getSubscriptionManager().addSubscriptionListener(new Gw06SubscriptionListener());
                        break;
                }

            }
            //订阅节点列表
            List<NodeId> list_node = new ArrayList<>();
            OpcNode opcNode=null;
            if (gw.equals("gw01")) {
                opcNode=new OpcNode(1);

                list_node.add(opcNode.node_gw01_engrgy_vol);
//                list_node.add(opcNode.node_gw01_engrgy_ele);
//                list_node.add(opcNode.node_gw01_engrgy_pow);
//                list_node.add(opcNode.node_gw01_engrgy_gas);
//                list_node.add(opcNode.node_gw01_engrgy_en);

            }else{
                opcNode=new OpcNode(2);
            }

            list_node.add(opcNode.node_fun_TOMES);
            list_node.add(opcNode.node_mes_mode);




            // 监控项请求列表
            List<MonitoredItemCreateRequest> requests = new ArrayList<>();

            for (NodeId nodeId : list_node) {

                MonitoringParameters parameters = new MonitoringParameters(subscription.nextClientHandle(), 10.0, // sampling
                        // interval
                        null, // filter, null means use default
                        Unsigned.uint(1), // queue size // 条数
                        true // discard oldest
                );
                // 创建订阅的变量， 创建监控项请 求
                MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(
                        new ReadValueId(nodeId, AttributeId.Value.uid(), null, null), MonitoringMode.Reporting,
                        parameters);
                requests.add(request);
            }

            BiConsumer<UaMonitoredItem, Integer> onItemCreated =
                    (item, id) -> item.setValueConsumer(this::onSubscriptionValueOfGw);

             subscription.createMonitoredItems(
                    TimestampsToReturn.Both,
                    requests,
                    onItemCreated
            ).get();

        } catch (Exception e) {
            e.printStackTrace();
            logger.info(gw+" 订阅失败");
        }
    }


    public void onSubscriptionValueOfGw(UaMonitoredItem item, DataValue value){
        String node_str= item.getReadValueId().getNodeId().getIdentifier().toString();
        String toDp="0";
        logger.info(node_str);

        switch (node_str){
            //case "3":
            case "15":
            case "\"OPC\".\"To_MES\".\"fun_site\"":
                String fun_str= (String) value.getValue().getValue();
                toDp=fun_str;
                logger.info("功能号:"+fun_str);
                //调用统一处理方法
                if (fun_str.length()==5) {
                    funOperate(fun_str);
                }
                break;
         //   case "4":
            case "16":
            case "\"OPC\".\"To_MES\".\"mes_mode\"":
                boolean mes_bl= (boolean) value.getValue().getValue();
                logger.info("MES模式:"+mes_bl);
                break;

            case "\"能源数据\".\"1_能源\".\"电压\"":
               float dy= (float) value.getValue().getValue();
                logger.info("工位1 电压:"+dy+ DateUtils.getTime());
                break;
        }
//        //统一数据发送
//        try {
//
//            WebSocketServer.sendInfo("refresh", "state_page");
//            WebSocketServer.sendInfo("refresh", "order_page");
//            WebSocketServer.sendInfo("refresh", "app");
////          发送给大屏 数据
//            WebSocketServer.sendInfo(toDp, "dp");
//
//        } catch (IOException e) {
//            e.printStackTrace();
//        }


    }


    //根据功能编号匹配操作
    public void funOperate(String fun_site){

        String fun=fun_site.substring(0,3); //功能号
        String site=fun_site.substring(3); //站点号

        logger.info("功能编号:"+fun+" 站点编号:"+site);
        OpcUaClient opc = (OpcUaClient) OpcUtil.mapOpcClient.get("gw"+site); //取OPC
        OpcNode opcNode=null;

        if(site.equals("01")){

            opcNode=new OpcNode(1);

        } else{
            opcNode=new OpcNode(2);

        }

        //读 OPC 数据
        ToMes toMes = opcService.readOpc(opc, opcNode);
        System.out.println(toMes);
        switch (fun){
            case "101":
                logger.info("询问订单");
                //1.查询计划
                FromMes fromMes = new FromMes();
                if(site.equals("04")){
                    fromMes= opcService.findWorkPlanByTray(site,Integer.valueOf(toMes.getTrayId()),false);
                }else{
                    fromMes= opcService.findWorkPlanByTray(site,Integer.valueOf(toMes.getTrayId()),true);
                }

                if (fromMes.getoId().equals("0000")) {
                    //没有订单 重置ToMes
                    fromMes.setoId("0002");
                    opcService.resetOpc(opc,opcNode );
                }
                System.out.println(fromMes);
                //2 写数据
                opcService.writeOpc(opc, fromMes,opcNode );

                break;
            case "102":
                logger.info("开始运行");
                //1.读数据

                //2.修改状态
                opcService.updateWpAndWpiAndOp(toMes);
                break;
            case "103":
                logger.info("完成操作");
                //1.读数据

                opcService.finWpAndWpiAndOp(toMes);
                //3.重置信息
                opcService.resetOpc(opc, opcNode);
                //如果是1号站点 需要从料仓取料
                if(site.equals("01")){
                    stockBinService.outStockBinByWpi(toMes);

                }
                //如果是6号站点 需要入成品库
                if(site.equals("06")){
                     //库位号
                    productStoreListService.takeInPS(Long.valueOf(toMes.getAreaNum()),toMes.getoId());

                }

                break;
            case "105":
                logger.info("开始录歌");
                //1.读数据

                //2.回数据 录歌成功！
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                FromMes fromMesMp3 = opcService.findParam(toMes);
                if (opcService.addFileToUpan(fromMesMp3.getParam01(), "0001.mp3")) {
                    System.out.println("录歌完成");
                }
                break;

            case "106":
                logger.info("开始打印");
                //1.读数据

                //2. 开始控制激光打印机使用 httpClient 并查找变量
                FromMes fromMes1 = opcService.findParam(toMes);
                try {
                    //opcService.printLight(fromMes1.getParam01());
                } catch (Exception e) {
                    System.out.println("打印机出问题");
                }
                break;
            case "110":
                logger.info("不合格完成");
                //1.读数据
                opcService.finWpAndWpiAndOp(toMes);
                opcService.finAndUnWpAndWpiAndOp(toMes);
                //3.重置信息
                opcService.resetOpc(opc,opcNode );
                //3.入废品库
                if(site.equals("02")){

                }
                break;
        }
        //最后都需要回馈
        OpcClientUtil.write(opcNode.node_fun_site_FROMMES, fun_site, opc);

    }

}
